package com.devunion.salon.server.jpa.utils;

import com.devunion.salon.core.query.QueryBuilder;
import com.extjs.gxt.ui.client.Style;
import com.extjs.gxt.ui.client.data.ListLoadConfig;
import com.extjs.gxt.ui.client.data.ModelData;
import com.extjs.gxt.ui.client.data.PagingLoadConfig;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.orm.jpa.JpaCallback;
import org.springframework.orm.jpa.JpaTemplate;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceException;
import javax.persistence.Query;
import java.util.ArrayList;
import java.util.List;

/**
 * @author spetrakovsky
 */
public class ModelQueryHelper {

    private static final Log log = LogFactory.getLog(ModelQueryHelper.class);

    public static List<? extends ModelData> readData(List<Object[]> objects, String[] propertyNames, Class<? extends ModelData> modelClass) {
        List<ModelData> result = new ArrayList<ModelData>(objects.size());
        for (Object[] properties : objects) {
            try {
                ModelData data = modelClass.newInstance();
                for (int i = 0; i < propertyNames.length; i++) {
                    data.set(propertyNames[i], properties[i]);
                }
                result.add(data);
            } catch (InstantiationException e) {
                log.error(modelClass.getName() + " new instance error", e);
                break;
            } catch (IllegalAccessException e) {
                log.error(modelClass.getName() + " new instance error", e);
                break;
            }
        }
        return result;
    }

    public static String getSortProperty(ListLoadConfig config) {
        return config.getSortInfo().getSortField();
    }

    public static boolean isSortAscending(ListLoadConfig config) {
        return config.getSortInfo().getSortDir() == Style.SortDir.ASC || config.getSortInfo().getSortDir() == Style.SortDir.NONE;
    }

    public static List executeFind(JpaTemplate jpaTemplate, final ListLoadConfig config, final String select, final String alias, final Object[][] searchCardPropertiesMapper) {
        return jpaTemplate.executeFind(new JpaCallback() {
            public Object doInJpa(EntityManager em) throws PersistenceException {
                boolean asc = isSortAscending(config);
                String sortField = getSortProperty(config);
                QueryBuilder qb = new QueryBuilder(alias, sortField, asc);
                if (searchCardPropertiesMapper != null) {
                    qb.appendAndCondition(config, searchCardPropertiesMapper);
                }
                StringBuilder builder = qb.getQuery();
                builder.insert(0, select);
                Query query = em.createQuery(builder.toString());
                if (config instanceof PagingLoadConfig) {
                    PagingLoadConfig paggingConfig = (PagingLoadConfig) config;
                    query.setFirstResult(paggingConfig.getOffset());
                    query.setMaxResults(paggingConfig.getLimit());
                }
                Object[] values = qb.getParameters();
                if (values != null) {
                    for (int i = 0; i < values.length; i++) {
                        query.setParameter(i + 1, values[i]);
                    }
                }
                return query.getResultList();
            }
        });
    }

    public static Object executeCount(JpaTemplate jpaTemplate, final ListLoadConfig config, final String select, final String alias, final Object[][] searchCardPropertiesMapper) {
        return jpaTemplate.execute(new JpaCallback() {
            public Object doInJpa(EntityManager em) throws PersistenceException {
                QueryBuilder qb = new QueryBuilder(alias);
                if (searchCardPropertiesMapper != null) {
                    qb.appendAndCondition(config, searchCardPropertiesMapper);
                }
                StringBuilder builder = qb.getQuery();
                builder.insert(0, select);
                Query query = em.createQuery(builder.toString());
                Object[] values = qb.getParameters();
                if (values != null) {
                    for (int i = 0; i < values.length; i++) {
                        query.setParameter(i + 1, values[i]);
                    }
                }
                return query.getSingleResult();
            }
        });
    }

}
